﻿using System;
using System.ComponentModel.DataAnnotations;
using System.Security.Cryptography;
using System.Text;

namespace CommonNet48.Encrypt
{
    /// <summary>
    /// RSA秘钥实体类
    /// </summary>
    public class RSAKey
    {
        /// <summary>
        /// 加密秘钥xml
        /// </summary>
        [Display(Name = "xml加密秘钥")]
        public string PublicKey { get; set; } = string.Empty;

        /// <summary>
        /// 解密秘钥xml
        /// </summary>
        [Display(Name = "xml解密秘钥")]
        public string PrivateKey { get; set; } = string.Empty;

        /// <summary>
        /// 公钥(用于Jwt鉴权)
        /// </summary>
        [Display(Name = "加密秘钥")]
        public RSAParameters PublicKeys { get; set; } = new RSAParameters();

        /// <summary>
        /// 私钥(用于Jwt鉴权)
        /// </summary>
        [Display(Name = "解密秘钥")]
        public RSAParameters PrivateKeys { get; set; } = new RSAParameters();


        /// <summary>
        /// 构造
        /// </summary>
        public RSAKey()
        {

        }
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="publicKey">加密秘钥(xml)</param>
        /// <param name="privateKey">解密秘钥(xml)</param>
        /// <param name="publicKeys">公钥(用于Jwt鉴权)</param>
        /// <param name="privateKeys">私钥(用于Jwt鉴权)</param>
        public RSAKey(string publicKey, string privateKey, RSAParameters publicKeys, RSAParameters privateKeys)
        {
            this.PublicKey = publicKey;
            this.PrivateKey = privateKey;
            this.PublicKeys = publicKeys;
            this.PrivateKeys = privateKeys;
        }
    }

    /// <summary>
    /// RSA加密解密帮助类
    /// </summary>
    public class RSAHelper
    {
        /// <summary>
        /// 获取加密秘钥(PublicKey)和解密秘钥(PrivateKey)
        /// </summary>
        /// <returns>加密秘钥(PublicKey)和解密秘钥对</returns>
        public static RSAKey GetKeyPair()
        {
            using (var rsa = new RSACryptoServiceProvider(2048))
            {
                try
                {
                    string publicKey = rsa.ToXmlString(false);
                    string privateKey = rsa.ToXmlString(true);
                    RSAParameters publicKeys = rsa.ExportParameters(false);
                    RSAParameters privateKeys = rsa.ExportParameters(true);
                    return new RSAKey(publicKey, privateKey, publicKeys, privateKeys);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    rsa.PersistKeyInCsp = false;
                    return null;
                }
            }
        }

        /// <summary>
        /// RSA 加密
        /// </summary>
        /// <param name="content">明文(待加密)</param>
        /// <param name="publicKey">加密key</param>
        /// <returns>加密后的密文</returns>
        public static string Encrypt(string content, string publicKey)
        {
            using (var rsa = new RSACryptoServiceProvider(2048))
            {
                rsa.FromXmlString(publicKey);
                byte[] dataToEncrypt = Encoding.UTF8.GetBytes(content);
                byte[] resultBytes = rsa.Encrypt(dataToEncrypt, false);
                return Convert.ToBase64String(resultBytes);
            }
        }

        /// <summary>
        /// RSA 解密
        /// </summary>
        /// <param name="content">密文(待解密)</param>
        /// <param name="privateKey">解密key</param>
        /// <returns>解密后的明文</returns>
        public static string Decrypt(string content, string privateKey)
        {
            byte[] dataToDecrypt = Convert.FromBase64String(content);
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(2048);
            RSA.FromXmlString(privateKey);
            byte[] resultBytes = RSA.Decrypt(dataToDecrypt, false);
            return Encoding.UTF8.GetString(resultBytes);
        }


        /// <summary>
        /// 加密并返回秘钥
        /// </summary>
        /// <param name="content">明文(待加密)</param>
        /// <param name="rsaKey">生成的秘钥对</param>
        /// <returns>加密后的密文</returns>
        public static string Encrypt(string content, out RSAKey rsaKey)
        {
            rsaKey = GetKeyPair();
            return Encrypt(content, rsaKey.PublicKey);
        }

    }
}
